/*************************************************************************************************
 * @brief    闪存管理器
 * Change Logs:
 * Date           Author         Email            Notes
 * 2025-01-10     子恒     3393018959@qq.com    初版完成
 * 2025-06-19     子恒     3393018959@qq.com    奇葩芯片还可以从0写成1，防止此类情况发生
 * 2025-09-10     子恒     3393018959@qq.com    index只在初始化时从flash加载一次，之后随ram更新
 *************************************************************************************************/

#define _B_FLASH_GLOBALS_
#include "b_flash.h"

#if ((B_FLASH_LOG_DEBUG_EN != 0) || (B_FLASH_LOG_INFO_EN != 0))
const char mode_log[2][10] = {"main", "back"};
#endif

static void dump_hex(const unsigned char *data, size_t length)
{
#if (B_FLASH_LOG_DEBUG_EN != 0)
  for (size_t i = 0; i < length; i++)
  {
    B_FLASH_DEBUG_PRINTF("%02X ", data[i]);
  }
  B_FLASH_DEBUG_PRINTF("\n");
#endif
}

static uint32_t get_check_sum(uint8_t *pdata, uint32_t size)
{
  uint32_t tmp = 0;
  for (uint32_t i = 0; i < size; i++)
  {
    tmp += pdata[i];
  }
  return tmp;
}

static uint32_t get_address(b_flash_manager_t *flash_manager, index_mode_t mode)
{
  if (mode == INDEX_MAIN)
  {
    return flash_manager->user_init.main_flash_address;
  }
#if (BACK_FUNCTION_EN == 1)
  if (mode == INDEX_BACK)
  {
    return flash_manager->user_init.back_flash_address;
  }
#endif
  B_FLASH_INFO_PRINTF("[INFO]<b_flash_read_index mode is err>\r\n");
  return 0;
}

// 辅助函数：查找32位数据中第一个为1的位位置(0-31)，未找到返回-1
static int find_first_set_bit(uint32_t value)
{
  if (value == 0)
  {
    return -1;
  }

  int pos = 0;
  // 二分查找法定位第一个为1的位
  if ((value & 0xFFFF0000) == 0)
  {
    pos += 16;
    value <<= 16;
  }
  if ((value & 0xFF000000) == 0)
  {
    pos += 8;
    value <<= 8;
  }
  if ((value & 0xF0000000) == 0)
  {
    pos += 4;
    value <<= 4;
  }
  if ((value & 0xC0000000) == 0)
  {
    pos += 2;
    value <<= 2;
  }
  if ((value & 0x80000000) == 0)
  {
    pos += 1;
  }
  return pos;
}

static uint32_t b_flash_read_index(b_flash_manager_t *flash_manager, index_mode_t mode)
{
  uint32_t index = 0xffffffff;
  uint32_t address = get_address(flash_manager, mode);

  // 遍历标识区，找到第一个不为0的bit
  for (uint16_t i = 0; i < flash_manager->_info.flag_map_number; i++)
  {
    uint32_t tmp;
    flash_manager->user_init.pf_read((address + i * 4), &tmp, 4);
    B_FLASH_INFO_PRINTF("[INFO]<b_flash_read_index 0x%08x>\r\n", tmp);

    // 查找当前32位数据中第一个为1的位
    int j = find_first_set_bit(tmp);
    if (j != -1)
    {
      index = i * 32 + j;

      // 检查是否超过最大bit数
      if (index >= flash_manager->_info.flag_map_bit_number)
      {
        index = flash_manager->_info.flag_map_bit_number;
      }
      return index;
    }
  }

  return index;
}

static uint32_t get_cur_index(b_flash_manager_t *flash_manager, index_mode_t mode)
{
  if (mode == INDEX_MAIN)
  {
    return flash_manager->_info.main_index;
  }
  if (mode == INDEX_BACK)
  {
    return flash_manager->_info.back_index;
  }
  return 0xffffffff;
}

static uint32_t b_flash_add_index(b_flash_manager_t *flash_manager, index_mode_t mode)
{
  // 找到当前可写位置
  uint32_t index = get_cur_index(flash_manager, mode);
  uint32_t address = get_address(flash_manager, mode);

  uint32_t i = index / 32;
  uint32_t j = ((0x7FFFFFFF) >> (index % 32));
  i = address + i * 4;
  flash_manager->user_init.pf_write(i, &j, 4);
  if (mode == INDEX_MAIN)
  {
    flash_manager->_info.main_index++;
    B_FLASH_DEBUG_PRINTF("[DEBUG][main]<b_flash_add_index %d %d address %08x is %08x>\r\n", index, flash_manager->_info.main_index, i, j);
  }
  if (mode == INDEX_BACK)
  {
    flash_manager->_info.back_index++;
    B_FLASH_DEBUG_PRINTF("[DEBUG][back]<b_flash_add_index %d %d address %08x is %08x>\r\n", index, flash_manager->_info.main_index, i, j);
  }
  return index;
}

static int8_t flash_read_select(b_flash_manager_t *flash_manager, void *read_data, uint32_t size, index_mode_t mode)
{
  int8_t check_pass = -1;

  uint32_t index = get_cur_index(flash_manager, mode);
  uint32_t address = get_address(flash_manager, mode);

  address = address + flash_manager->_info.flag_map_number * 4 + (flash_manager->_info.data_word_number * (index - 1)) * 4;

  flash_manager->user_init.pf_read(address, read_data, size);

  B_FLASH_DEBUG_PRINTF("[DEBUG][READ][%s][DATA]<address %08x><inxde %d>\r\n", mode_log[mode], address, index);
  dump_hex(read_data, size);

  if (flash_manager->user_init.pf_check != NULL)
  {
    check_pass = flash_manager->user_init.pf_check(read_data, size);
    if (check_pass != 0)
    {
      B_FLASH_INFO_PRINTF("[INFO][READ][%s]<pf_check err %d>\r\n", mode_log[mode], check_pass);
      return check_pass;
    }
  }

  check_pass = -1;
  // 读校验地址数据
  uint32_t check_sum;
  uint32_t check_sum_address = address + (flash_manager->_info.data_word_number - 1) * 4;

  flash_manager->user_init.pf_read(check_sum_address, &check_sum, 4);
  // 对数据和校验地址求校验
  uint32_t check_sum_calc = get_check_sum(read_data, size) + check_sum_address;

  if (check_sum == check_sum_calc)
  {
    check_pass = 0;
  }

  B_FLASH_DEBUG_PRINTF("[DEBUG][READ][%s][CHECK]<address %08x check %08x calc %08x>\r\n", mode_log[mode], check_sum_address, check_sum, check_sum_calc);
  dump_hex((uint8_t *)(&check_sum), 4);

  return check_pass;
}

static int8_t flash_write_select(b_flash_manager_t *flash_manager, void *wirte_data, uint32_t size, index_mode_t mode)
{
  int8_t ret = 0;
  uint32_t index = b_flash_add_index(flash_manager, mode);
  uint32_t address = get_address(flash_manager, mode);

  if (flash_manager->user_init.pf_check != NULL)
  {
    ret = flash_manager->user_init.pf_check(wirte_data, size);
    if (ret != 0)
    {
      B_FLASH_INFO_PRINTF("[INFO][READ][%s]<pf_check err %d reset default value>\r\n", mode_log[mode], ret);
      if (flash_manager->user_init.pf_default != NULL)
        flash_manager->user_init.pf_default(wirte_data, size);
    }
  }

  if (index >= flash_manager->_info.flag_map_bit_number)
  {
    B_FLASH_INFO_PRINTF("[INFO]<erase address %08x page %d>\r\n", address, flash_manager->user_init.flash_page_numbre);
    ret |= flash_manager->user_init.pf_erase(address, flash_manager->user_init.flash_page_numbre);
    if (mode == INDEX_MAIN)
    {
      flash_manager->_info.main_index = 0;
    }
    else if (mode == INDEX_BACK)
    {
      flash_manager->_info.back_index = 0;
    }
    index = b_flash_add_index(flash_manager, mode);
  }

  // 从选区找最新地址写
  address = address + flash_manager->_info.flag_map_number * 4 + flash_manager->_info.data_word_number * index * 4;
  ret |= flash_manager->user_init.pf_write(address, wirte_data, size);

  B_FLASH_DEBUG_PRINTF("[DEBUG][WRIET][%s][DATA]<address %08x><inxde %d>\r\n", mode_log[mode], address, index);
  dump_hex((uint8_t *)(wirte_data), size);

  // 如果不是第一个位置，就把前面位置的数据打坏
  if (index != 0)
  {
    uint32_t tmp = 0;
    ret |= flash_manager->user_init.pf_write(address - 4, &tmp, 4);
  }

  // 写校验数据到选区
  uint32_t check_sum_address = address + (flash_manager->_info.data_word_number - 1) * 4;
  uint32_t check_sum = get_check_sum(wirte_data, size) + check_sum_address;
  ret |= flash_manager->user_init.pf_write(check_sum_address, (uint8_t *)&check_sum, 4);

  B_FLASH_DEBUG_PRINTF("[DEBUG][WRITE][%s][CHECK]<address %08x check %08x>\r\n", mode_log[mode], check_sum_address, check_sum);
  dump_hex((uint8_t *)(&check_sum), 4);
  return ret;
}

int8_t b_flash_read(b_flash_manager_t *flash_manager, void *read_data, uint32_t size)
{
  int8_t check_main_pass, check_back_pass;

  for (uint8_t i = 0; i < FLASH_READ_MAX_CNT; i++)
  {
    check_main_pass = flash_read_select(flash_manager, read_data, size, INDEX_MAIN);
    if (check_main_pass == 0)
      break;
  }
#if (BACK_FUNCTION_EN == 1)
  for (uint8_t i = 0; i < FLASH_READ_MAX_CNT; i++)
  {
    check_back_pass = flash_read_select(flash_manager, read_data, size, INDEX_BACK);
    if (check_back_pass == 0)
      break;
  }
  // 如果两个区都不通过，则复位整个扇区数据,写入默认数据
  if ((check_main_pass != 0) && (check_back_pass != 0))
  {
    B_FLASH_INFO_PRINTF("[INFO][error]<Restore the sector to default data.>\r\n");
    flash_manager->user_init.pf_erase(flash_manager->user_init.main_flash_address, flash_manager->user_init.flash_page_numbre);
    flash_manager->user_init.pf_erase(flash_manager->user_init.back_flash_address, flash_manager->user_init.flash_page_numbre);
    if (flash_manager->user_init.pf_default != NULL)
      flash_manager->user_init.pf_default(read_data, size);
    b_flash_write(flash_manager, read_data, size);
    return 1;
  }

  // 如果主区不通过，备份区通过，擦除主区，重写标识，把备份区数据写入
  if ((check_main_pass != 0) && (check_back_pass == 0))
  {
    B_FLASH_INFO_PRINTF("[INFO][error]<main flash Data is incorrect, rewrite the flash.>\r\n");
    flash_manager->user_init.pf_erase(flash_manager->user_init.main_flash_address, flash_manager->user_init.flash_page_numbre);
    flash_read_select(flash_manager, read_data, size, INDEX_BACK);
    flash_write_select(flash_manager, read_data, size, INDEX_MAIN);
    return 1;
  }

  // 如果主区通过，备份区不通过，擦除备份区，重写标识，读主区数据写入
  if ((check_back_pass != 0) && (check_main_pass == 0))
  {
    B_FLASH_INFO_PRINTF("[INFO][error]<back flash Data is incorrect, rewrite the flash.>\r\n");
    flash_manager->user_init.pf_erase(flash_manager->user_init.back_flash_address, flash_manager->user_init.flash_page_numbre);
    flash_read_select(flash_manager, read_data, size, INDEX_MAIN);
    flash_write_select(flash_manager, read_data, size, INDEX_BACK);
    return 1;
  }
#endif
  return check_main_pass;
}

int8_t b_flash_create(b_flash_manager_t *flash_manager, void *wirte_data, uint32_t size)
{
  if (flash_manager->user_init.pf_write == NULL)
  {
    B_FLASH_INFO_PRINTF("[INFO][ERROR]<pf_write is null>");
    return 1;
  }

  if (flash_manager->user_init.pf_read == NULL)
  {
    B_FLASH_INFO_PRINTF("[INFO][ERROR]<pf_read is null>");
    return 1;
  }

  if (flash_manager->user_init.pf_erase == NULL)
  {
    B_FLASH_INFO_PRINTF("[INFO][ERROR]<pf_erase is null>");
    return 1;
  }

  if (flash_manager->user_init.pf_default == NULL)
  {
    B_FLASH_INFO_PRINTF("[INFO][WARNING]<pf_default is null>");
    return 1;
  }

  if (flash_manager->user_init.pf_check == NULL)
  {
    B_FLASH_INFO_PRINTF("[INFO][WARNING]<pf_check is null>");
    return 1;
  }

  if (flash_manager->user_init.main_flash_address & 0x03)
  {
    B_FLASH_INFO_PRINTF("[INFO][WARNING]<main_flash_address no 4-byte aligned>");
    return 1;
  }
#if (BACK_FUNCTION_EN == 1)
  if (flash_manager->user_init.back_flash_address & 0x03)
  {
    B_FLASH_INFO_PRINTF("[INFO][WARNING]<back_flash_address no 4-byte aligned>");
    return 1;
  }
#endif
  // 数据块字数，多占一个字用来存校验数据
  flash_manager->_info.data_word_number = (size + 3) / 4 + 1;
  flash_manager->_info.flag_map_number = (flash_manager->user_init.flash_page_size * flash_manager->user_init.flash_page_numbre) / 128;
  flash_manager->_info.flag_map_bit_number = ((flash_manager->user_init.flash_page_size * flash_manager->user_init.flash_page_numbre) / 4 - flash_manager->_info.flag_map_number) / flash_manager->_info.data_word_number;

  B_FLASH_INFO_PRINTF("[INFO][INIT]<data_word = %d, flag_map_number = %d flag_map_bit_number = %d>\r\n", flash_manager->_info.data_word_number, flash_manager->_info.flag_map_number, flash_manager->_info.flag_map_bit_number);

  // 写标识区
  uint32_t index;
  flash_manager->user_init.pf_read(flash_manager->user_init.main_flash_address, (uint8_t *)(&index), 4);
  index &= 0x7FFFFFFF;
  flash_manager->user_init.pf_write(flash_manager->user_init.main_flash_address, (uint8_t *)(&index), 4);
  flash_manager->user_init.pf_read(flash_manager->user_init.main_flash_address, (uint8_t *)(&index), 4);
  B_FLASH_INFO_PRINTF("[INFO][INIT]<index = %x\r\n>", index);

#if (BACK_FUNCTION_EN == 1)
  flash_manager->user_init.pf_read(flash_manager->user_init.back_flash_address, (uint8_t *)(&index), 4);
  index &= 0x7FFFFFFF;
  flash_manager->user_init.pf_write(flash_manager->user_init.back_flash_address, (uint8_t *)(&index), 4);
  flash_manager->user_init.pf_read(flash_manager->user_init.back_flash_address, (uint8_t *)(&index), 4);
  B_FLASH_INFO_PRINTF("[INFO][INIT]<index = %x\r\n>", index);
#endif

  flash_manager->_info.main_index = b_flash_read_index(flash_manager, INDEX_MAIN);
  flash_manager->_info.back_index = b_flash_read_index(flash_manager, INDEX_BACK);

  b_flash_read(flash_manager, wirte_data, size);
  return 0;
}

int8_t b_flash_write(b_flash_manager_t *flash_manager, void *wirte_data, uint32_t size)
{
  uint8_t ret = 0;
  ret |= flash_write_select(flash_manager, wirte_data, size, INDEX_MAIN);
#if (BACK_FUNCTION_EN == 1)
  ret |= flash_write_select(flash_manager, wirte_data, size, INDEX_BACK);
#endif
  return ret;
}
